/* jshint esversion: 7 */
/*jshint -W069 */
const fs = require("fs");
const path = require("path");

module.exports = class Logger{
    constructor(name, level, isOutput, isWrite, writeLevel){
        this.name = name ?? "";
        this.level = level ?? 4;
        this.isOutput = isOutput ?? true;
        this.isWrite = isWrite ?? true;
        this.writeLevel = writeLevel ?? 5;
        this.streams = new Map(); // 添加流缓存
        this.streamTimeout = 30000; // 30秒无操作后关闭流
    }
    info(...args){
        let text = argsJoin(args);
        if (this.level>=1 && this.isOutput == true){
            console.log(`\x1b[92m${now()} \x1b[96mINFO [${this.name}] \x1b[92m${text}\x1b[0m`);     
        }
        if (this.writeLevel>=1 && this.isWrite){
            this.write('console', 'console', `[INFO] ${text}`);
        }
    }
    warn(...args){
        let text = argsJoin(args);
        if (this.level>=2 && this.isOutput == true){
            console.log(`\x1b[92m${now()} \x1b[93mWARN [${this.name}] ${text}\x1b[0m`);
        }
        if (this.writeLevel>=2 && this.isWrite){
            this.write('console', 'console', `[WARN] ${text}`);
        }
    }
    error(...args){
        let text = argsJoin(args);
        if (this.level>=3 && this.isOutput == true){
            console.log(`\x1b[92m${now()} \x1b[91mERROR [${this.name}] ${text}\x1b[0m`);
        }
        if (this.writeLevel>=3 && this.isWrite){
            this.write('console', 'console', `[ERROR] ${text}`);
        }
    }
    fatal(...args){
        let text = argsJoin(args);
        if (this.level>=4 && this.isOutput == true){
            console.log(`\x1b[92m${now()} \x1b[31mFATAL [${this.name}] ${text}\x1b[0m`);
        }
        if (this.writeLevel>=4 && this.isWrite){
            this.write('console', 'console', `[FATAL] ${text}`);
        }
    }
    debug(...args){
        let text = argsJoin(args);
        if (this.level>=5 && this.isOutput == true){
            console.log(`\x1b[92m${now()} \x1b[0mDEBUG [${this.name}] ${text}\x1b[0m`);
        }
        if (this.writeLevel>=5 && this.isWrite){
            this.write('console', 'console', `[DEBUG] ${text}`);
        }
    }
    setConsole(isOutput, lev){
        if (!(/(^[2-5]$)/.test(lev))){
            console.log(`\x1b[92m${now()} \x1b[91mERROR [${this.name}] Logger等级须为2-5的正整数\x1b[0m`);
            return false;
        }
        this.level = Number(lev);
        this.isOutput = isOutput;
        //this.warn(`日志等级调整为: ${this.level}`);
        return true;
    }
    write(folderName, fileName, ...args){
        let text = argsJoin(args);
        let date = new Date();
        let filePath = `./logs/${this.name}/${folderName}/${fileName}_${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}.txt`;
        let fileDirPath = path.dirname(filePath);
        if (!fs.existsSync(fileDirPath)){
            fs.mkdirSync(fileDirPath, {recursive:true});
        }

        // 获取或创建流
        let streamKey = `${folderName}_${fileName}`;
        let streamInfo = this.streams.get(streamKey);

        // 如果流不存在或已关闭，则创建新流
        if (!streamInfo || streamInfo.stream.destroyed) {
            const writeStream = fs.createWriteStream(filePath, { flags: 'a' });
            streamInfo = {
                stream: writeStream,
                timeout: null
            };
            this.streams.set(streamKey, streamInfo);
        }

        // 清除现有超时，重置关闭计时器
        if (streamInfo.timeout) {
            clearTimeout(streamInfo.timeout);
        }

        // 写入数据
        streamInfo.stream.write(`[${logTime()}]${text}\n`);

        // 设置超时关闭流
        streamInfo.timeout = setTimeout(() => {
            streamInfo.stream.end();
            this.streams.delete(streamKey);
        }, this.streamTimeout);

        // fs.appendFile(
        //     filePath, 
        //     `\n[${logTime()}]${text}`, 
        //     (err)=>{
        //         if (err) { 
        //             console.error(err); 
        //         }
        //     }
        // );
    }
    query(){
        return this.level;
    }
};

function argsJoin(args){
    return args.map(arg => {
        if (arg instanceof Error) {
            return `${arg.message}\n${arg.stack}`;
        }
        if (arg instanceof Object){
            try {
                return JSON.stringify(arg, null, 2);
            } catch (e) {
                return String(arg);
            }
        }
        return String(arg);
    }).join(" ");
}

function logTime(){
  let date = new Date();
  return `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
}

function now(){
  let date = new Date();
  return [date.toTimeString().slice(0, 8)].join('');
}